package com.linq.cool.beauty.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linq.cool.beauty.domain.BeautyBrand;
import com.linq.cool.beauty.domain.BeautyEsProduct;
import com.linq.cool.beauty.domain.BeautyProduct;
import com.linq.cool.beauty.domain.BeautyProductCategory;
import com.linq.cool.beauty.dto.BeautyProductDTO;
import com.linq.cool.beauty.dto.BeautyProductQueryDTO;
import com.linq.cool.beauty.dto.BeautyProductSearchDTO;
import com.linq.cool.beauty.mapper.BeautyProductMapper;
import com.linq.cool.beauty.service.BeautyBrandService;
import com.linq.cool.beauty.service.BeautyProductCategoryService;
import com.linq.cool.beauty.service.BeautyProductService;
import com.linq.cool.beauty.vo.BeautyProductVO;
import com.linq.cool.common.constants.Constants;
import com.linq.cool.common.constants.UserConstants;
import com.linq.cool.common.core.domain.PageVO;
import com.linq.cool.common.core.exception.BusinessException;
import com.linq.cool.common.core.utils.BeanUtils;
import com.linq.cool.common.core.utils.IdWorker;
import com.linq.cool.common.core.utils.SecurityUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yqlin
 * @Date: 2021/2/5 17:25
 * @Description:
 * @Version: 1.0.0
 */

@Service
public class BeautyProductServiceImpl extends ServiceImpl<BeautyProductMapper, BeautyProduct> implements BeautyProductService {
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private BeautyProductCategoryService beautyProductCategoryService;
    @Autowired
    private BeautyBrandService beautyBrandService;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public IPage<BeautyProduct> listByPage(IPage<BeautyProduct> page, BeautyProductQueryDTO dto) {
        return this.page(page, this.getLambdaQueryWrapper(dto));
    }

    @Override
    public boolean saveProduct(BeautyProductDTO dto) {
        BeautyProduct product = new BeautyProduct();
        BeanUtils.copyProperties(dto, product);
        product.setId(idWorker.nextId());
        // 处理轮播图 没有放置轮播图的时候就默认用 商品图片替代
        if (StringUtils.isBlank(dto.getAlbumPics())) {
            product.setAlbumPics(dto.getPic());
        }
        // 为了保证相对安全性 品牌和分类 查出来判断
        BeautyBrand curBrand = beautyBrandService.getById(dto.getBrandId());
        if (null == curBrand) {
            throw new BusinessException("该品牌不存在");
        }
        product.setBrandName(curBrand.getName());
        BeautyProductCategory curProductCategory = beautyProductCategoryService.getById(dto.getProductCategoryId());
        if (null == curProductCategory) {
            throw new BusinessException("该分类不存在");
        }
        product.setCreator(SecurityUtils.getUserId());
        return this.save(product);
    }

    @Override
    public boolean updateProduct(BeautyProductDTO dto) {
        BeautyProduct product = new BeautyProduct();
        BeanUtils.copyProperties(dto, product);
        BeautyProduct curProduct = this.getById(dto.getId());
        if (null == curProduct) {
            throw new BusinessException("该商品不存在");
        }
        // 为了保证相对安全性 品牌和分类 查出来判断
        BeautyBrand curBrand = beautyBrandService.getById(dto.getBrandId());
        if (null == curBrand) {
            throw new BusinessException("该品牌不存在");
        }
        product.setBrandName(curBrand.getName());
        BeautyProductCategory curProductCategory = beautyProductCategoryService.getById(dto.getProductCategoryId());
        if (null == curProductCategory) {
            throw new BusinessException("该分类不存在");
        }
        // 处理轮播图 没有放置轮播图的时候就默认用 商品图片替代
        if (StringUtils.isBlank(dto.getAlbumPics())) {
            product.setAlbumPics(dto.getPic());
        }

        product.setModifier(SecurityUtils.getUserId()).setGmtModified(new Date());
        return this.updateById(product);
    }

    @Override
    public BeautyProductVO getProductById(Long productId) {
        // 根据id查询
        BeautyProduct product = this.getById(productId);
        if (null == product) {
            throw new BusinessException("该商品不存在");
        }
        BeautyProductVO vo = new BeautyProductVO();
        BeanUtils.copyProperties(product, vo);
        // 处理productCategoryIds 回显使用
        // 拿到子节点id
        Long productCategoryId = product.getProductCategoryId();
        Deque<Long> deque = new ArrayDeque<>(4);
        // 不是顶级 0
        while (null != productCategoryId && !productCategoryId.equals(UserConstants.DEFAULT_PARENT_ID)) {
            // 根据子节点ID查询分类
            BeautyProductCategory productCategory = beautyProductCategoryService.getById(productCategoryId);
            if (null != productCategory) {
                // 入队列
                deque.push(productCategory.getId());
                productCategoryId = productCategory.getParentId();
            } else {
                break;
            }
        }
        // 封装到vo里
        vo.setProductCategoryIds(new ArrayList<>(deque));
        return vo;
    }

    @Override
    public List<BeautyProduct> listByNewStatus() {
        return baseMapper.listByNewStatus();
    }

    @Override
    public List<BeautyProduct> listByRecommendStatus() {
        return baseMapper.listByRecommendStatus();
    }

    @Override
    public List<BeautyProduct> listBySale(Long productId) {
        BeautyProduct product = this.getById(productId);
        if (null == product) {
            throw new BusinessException("该商品不存在");
        }
        return baseMapper.listBySale(product);
    }

    @Override
    public PageVO search(BeautyProductSearchDTO dto) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 构造查询条件
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getKeyword(),
                                                                "name", "pDesc", "content", "brand_name"
            ));
        }
        if (dto.getProductCategoryId() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("product_category_id", dto.getProductCategoryId()));
        }
        if (dto.getBrandId() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("brand_id", dto.getBrandId()));
        }
        if (dto.getPriceStart() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(dto.getPriceStart()));
        }
        if (dto.getPriceEnd() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(dto.getPriceEnd()));
        }
        queryBuilder.withQuery(boolQueryBuilder);
        // 构造分页
        queryBuilder.withPageable(PageRequest.of(dto.getCurrent() - 1, dto.getSize()));
        // 排序
        String sortFiled = UserConstants.getSortField(dto.getSortWay());
        if (StringUtils.isNotBlank(sortFiled)) {
            SortOrder order = SortOrder.DESC;
            // 正序
            if (UserConstants.StateEnum.SORT_TYPE_ASC.getCode().equals(dto.getSortType())) {
                order = SortOrder.ASC;
            }
            queryBuilder.withSort(SortBuilders.fieldSort(sortFiled).order(order));
        }
        SearchHits<BeautyEsProduct> hits = elasticsearchRestTemplate.search(queryBuilder.build(), BeautyEsProduct.class);
        return new PageVO().setTotal(hits.getTotalHits()).setRecords(hits.get().map(SearchHit::getContent).collect(Collectors.toList()));
    }

    private LambdaQueryWrapper<BeautyProduct> getLambdaQueryWrapper(BeautyProductQueryDTO dto) {
        return new LambdaQueryWrapper<BeautyProduct>()
                .eq(BeautyProduct::getIsDeleted, UserConstants.StateEnum.DELETE_FLAG_EXIST.getCode())
                .eq(StringUtils.checkValNotNull(dto.getStatus()), BeautyProduct::getStatus, UserConstants.StateEnum.STATUS_NORMAL.getCode())
                .eq(StringUtils.checkValNotNull(dto.getNewStatus()), BeautyProduct::getNewStatus, dto.getNewStatus())
                .eq(StringUtils.checkValNotNull(dto.getProductCategoryId()), BeautyProduct::getProductCategoryId, dto.getProductCategoryId())
                .eq(StringUtils.checkValNotNull(dto.getPublishStatus()), BeautyProduct::getPublishStatus, dto.getPublishStatus())
                .eq(StringUtils.checkValNotNull(dto.getVerifyStatus()), BeautyProduct::getVerifyStatus, dto.getVerifyStatus())
                .like(StringUtils.checkValNotNull(dto.getName()), BeautyProduct::getName, dto.getName())
                .between(StringUtils.checkValNotNull(dto.getParams().get(Constants.BEGIN_TIME)), BeautyProduct::getGmtCreate, dto.getParams().get(Constants.BEGIN_TIME), dto.getParams().get(Constants.END_TIME))
                ;
    }
}
